package com.wzdigit.wms.wms.service.wms2sap;

import com.wzdigit.framework.exception.RestStatusException;
import com.wzdigit.wms.basic.domain.mapping.CodeMapping;
import com.wzdigit.wms.basic.domain.mid.IfPostback;
import com.wzdigit.wms.basic.domain.oqc.OqcInsp;
import com.wzdigit.wms.basic.domain.oqc.QmsOqc;
import com.wzdigit.wms.basic.enums.QaStatusEnum;
import com.wzdigit.wms.basic.enums.QmsOqcStatusEnum;
import com.wzdigit.wms.basic.enums.writeback.BackResultEnum;
import com.wzdigit.wms.basic.enums.writeback.OtherSystemEnum;
import com.wzdigit.wms.basic.enums.writeback.TopicEnum;
import com.wzdigit.wms.basic.mapper.core.oqc.QmsOqcMapper;
import com.wzdigit.wms.wms.client.web.service.common.wms2sap.ZDT_MsgHeader;
import com.wzdigit.wms.wms.client.web.service.common.wms2sap.ZDT_Reserve;
import com.wzdigit.wms.wms.client.web.service.wms2sap.check.*;
import com.wzdigit.wms.common.entity.StatusCode;
import com.wzdigit.wms.wms.service.mapping.CodeMappingNewService;
import com.wzdigit.wms.wms.service.mid.IfPostbackService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import java.io.StringWriter;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @version 1.0
 * @desc WMS TO SAP判检入库接口
 * @Author:yangwenbiao
 * @Date 2021/2/2 3:55 PM
 */
@Slf4j
@Service
public class ReportCheckService {

    @Autowired
    private QmsOqcMapper qmsOqcMapper;

    @Autowired
    private CodeMappingNewService codeMappingNewService;

    @Autowired
    private IfPostbackService ifPostbackService;

    @Value("${sap.web.service.protocol-head}")
    private String protocolHead;

    @Value("${sap.web.service.check-url}")
    private String checkUrl;

    @Value("${wzdigit.web.service.sap.ip}")
    private String ip;
    
    // 合格标识
    public static final String SUC_FLAG = "2";
    // 不合格标识
    public static final String FAIL_FLAG = "3";
    // 不合格-》合格标识
    public static final String FAIL_TO_SUC_FLAG = "4";
    
    private static final String WMS = "WMS";
    private static final String SAP = "SAP";

    /**
     * 【翻牌定时任务】调用
     * 向SAP报检且回写更新检验单
     * 
     * @param oqcInsp	检验单信息
     * @param factory	工厂组织
     * @param whsCode	仓库编码
     * @param count		翻牌数量
     * @param isCallQms 是否需要更新QMS状态
     * @return
     * @throws RestStatusException
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public boolean reportAndUpdateSchedule(OqcInsp oqcInsp, String factory, String whsCode, Integer count, boolean isCallQms) throws RestStatusException {
    	String loginName = "翻牌定时任务自动创建";
    	
    	// 新增回写表
    	IfPostback ifPostback = new IfPostback();
    	ifPostback.setCreateUser(loginName);
    	ifPostback.setCreateTime(new Date());
    	ifPostback.setPostbackNo(oqcInsp.getInspNo());	//送检单号
    	ifPostback.setDestSystem(OtherSystemEnum.SYSYTEM_SAP.getEnumName());
    	ifPostback.setPostbackTopic(TopicEnum.TOPIC_SAP_SEND_CHECK.getEnumName());
    	ifPostback.setPostbackResult(BackResultEnum.REPORT_CHECK_STATE.getCode());
    	ifPostbackService.addCheckOne(ifPostback);
        try {
            // 向SAP报检
            ZDT_080_RspRecord record = callSap(oqcInsp, factory, whsCode, count, ifPostback);
            if ("S".equals(record.getRESULT())) {
                log.info("【翻牌定时任务】回调SAP成功");
                
                // 更新检验单
                if(isCallQms) {
                	updateQmsOqc(record, oqcInsp.getQmsOqcId(), loginName);
                }
                
                // 更新回写表
                ifPostback.setReturnMessage(record.toString());
                ifPostback.setPostbackResult(BackResultEnum.REPORT_CHECK_SUC.getCode());
                ifPostbackService.updateOne(ifPostback);
                return true;
            } else {
            	log.info("【翻牌定时任务】回调SAP失败");
            	
            	// 更新回写表
            	ifPostback.setReturnMessage(record.toString());
            	ifPostback.setPostbackResult(BackResultEnum.REPORT_CHECK_FAIL.getCode());
                ifPostbackService.updateOne(ifPostback);
                return false;
            }
        } catch (Exception e) {
            log.error("【翻牌定时任务】回调SAP异常");

            // 更新回写表
            ifPostback.setReturnMessage(e.getMessage());
            ifPostback.setPostbackResult(BackResultEnum.REPORT_CHECK_ERROR.getCode());
            ifPostbackService.updateOne(ifPostback);
            return false;
        }
    }
    
    /**
     * 【立即报检】调用
     * 向SAP报检且回写更新检验单
     *
     * @param oqcInsp   	检验单信息
     * @param count     	送检数、产品数
     * @param loginName 	报检人
     * @return
     * @throws RestStatusException
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public boolean reportAndUpdateImmediately(OqcInsp oqcInsp, Integer count, String loginName) throws RestStatusException {
        ZDT_080_RspRecord record = new ZDT_080_RspRecord();
        if ("S".equals(record.getRESULT())) {
            // 成功，回写QMS_OQC
        	updateQmsOqc(record, oqcInsp.getQmsOqcId(), loginName);
        	return true;
        } else {
            // 抛出异常信息
            RestStatusException exception = new RestStatusException(record.getMSG());
            exception.setContent(record.getMSG());
            throw exception;
        }
    }

    /**
     * 【调SAP接口】
     * 
     * @param oqcInsp
     * @param factory
     * @param whsCode
     * @param count
     * @param ifPostback
     * @return
     * @throws RestStatusException
     */
    private ZDT_080_RspRecord callSap(OqcInsp oqcInsp, String factory, String whsCode, Integer count, IfPostback ifPostback) throws RestStatusException {
        try {
        	ZDT_080_RspRecord record = callSapDetail(oqcInsp, factory, whsCode, count, ifPostback);
        	return record;
        } catch (Exception e) {
            e.printStackTrace();

            // 抛出异常信息
            String msg = StatusCode.SAP_REPORT_CHECK_ERROR.message() + e.getMessage();
            RestStatusException exception = new RestStatusException(msg);
            exception.setContent(msg);
            throw exception;
        }
    }
    private ZDT_080_RspRecord callSapDetail(OqcInsp oqcInsp, String factory, String whsCode, Integer count, IfPostback ifPostback) {
    	log.info("开始报检......");
    	
    	// 【仓库映射关系表】
        Integer qaStatus = oqcInsp.getInspResult();
        CodeMapping codeMapping = codeMappingNewService.selectByWhsCodeAndFactory(factory, whsCode, qaStatus);
        if (codeMapping == null) {
        	String errMsg = String.format("根据工厂代码【%s】，WMS仓库CODE【%s】，QA_STATUS【%d】未找到对应仓库信息", factory, whsCode, qaStatus);
        	throw new RuntimeException(errMsg);
        }
    	
        // 【消息头】
        ZDT_MsgHeader header = new ZDT_MsgHeader();
        header.setSOURCE(WMS);
        header.setDESTINATION(SAP);
        header.setDATE(getDateStr());
        header.setTIME(getTimeStr());
        header.setSTATUS("");
        header.setMESSAGE("");

        // 【消息体】
        ZDT_080_ReqRecordsItems record = new ZDT_080_ReqRecordsItems();
        record.setID(String.valueOf(System.currentTimeMillis()));
        record.setAUFNR(oqcInsp.getPrdWo());				// 工单号
        record.setWERKS(factory);							// 工厂组织
        record.setLGORT(codeMapping.getMappingCode());		// 仓库code
        record.setMATNR(oqcInsp.getSkuCode());				// 物料code
        record.setMENGE(count.toString());					// 数量***
        record.setMAKTX("");								// 物料描述
        record.setAUART("");
        record.setZVBELN("");
        record.setZPOSNR("");
        record.setKDAUF("");
        record.setKDPOS("");
        record.setARBPL("");
        record.setKTEXT("");
        record.setDISPO("");
        
        // 【FLAG】
        if (oqcInsp.getInspResult().equals(QaStatusEnum.OK.getCode()) && (oqcInsp.getLastStatus() != null && oqcInsp.getLastStatus().equals(QmsOqcStatusEnum.CHECK_CONVICTED_BACK.getCode()))) {
            record.setFLAG(FAIL_TO_SUC_FLAG);	// 当前是【已通过】且 上一次是【已判退】【FLAG= 4】
        } else if (oqcInsp.getInspResult().equals(QaStatusEnum.NG.getCode())) {
            record.setFLAG(FAIL_FLAG);			// 不合格【已判退】【FLAG= 3】
        } else if (oqcInsp.getInspResult().equals(QaStatusEnum.OK.getCode())) {
            record.setFLAG(SUC_FLAG);			// 合格【已通过】【FLAG= 2】
        }

        // 【RSVA-RSV2】
        String rsvaRsv2 = null;
        if (record.getFLAG().equals(FAIL_TO_SUC_FLAG)) {
            // 改判的单都是从【不合格】仓调过去，故QA_STATUS写死2
            CodeMapping codeMappingChange = codeMappingNewService.selectByWhsCodeAndFactory(factory, whsCode, 2);
            if (codeMappingChange == null) {
                String errMsg = String.format("根据工厂代码【%s】，WMS仓库CODE【%s】，QA_STATUS【%d】未找到对应仓库信息", factory, whsCode, 2);
                throw new RuntimeException(errMsg);
            }
            rsvaRsv2 = codeMappingChange.getMappingCode();
        } else {
            // 合格、不合格状态都是从【待检仓】调过去，故QA_STATUS写死0
            CodeMapping codeMappingSucAndFail = codeMappingNewService.selectByWhsCodeAndFactory(factory, whsCode, 0);
            if (codeMappingSucAndFail == null) {
                String errMsg = String.format("根据工厂代码【%s】，WMS仓库CODE【%s】，QA_STATUS【%d】未找到对应仓库信息", factory, whsCode, 0);
                throw new RuntimeException(errMsg);
            }
            rsvaRsv2 = codeMappingSucAndFail.getMappingCode();
        }

        ZDT_Reserve rsva = new ZDT_Reserve();
        rsva.setRsv1(oqcInsp.getInspNo());
        rsva.setRsv2(rsvaRsv2);
        rsva.setRsv3("");
        rsva.setRsv4("");
        rsva.setRsv5("");
        record.setRSV_A(rsva);

        ZDT_Reserve rsvb = new ZDT_Reserve();
        rsvb.setRsv1("");
        rsvb.setRsv2("");
        rsvb.setRsv3("");
        rsvb.setRsv4("");
        rsvb.setRsv5("");
        record.setRSV_B(rsvb);

        ZDT_Reserve rsvc = new ZDT_Reserve();
        rsvc.setRsv1("");
        rsvc.setRsv2("");
        rsvc.setRsv3("");
        rsvc.setRsv4("");
        rsvc.setRsv5("");
        record.setRSV_C(rsvc);
        
        // 是否需要发送请求
        boolean sendFlag = true;
        
        // 【请求的核心报文】
        String sendXML = null;
        try {
            // 格式化生成的XML报文
        	Writer writer = new StringWriter();
            JAXBContext jc = JAXBContext.newInstance(ZDT_080_ReqRecordsItems.class);
            Marshaller ms = jc.createMarshaller();
            ms.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            ms.marshal(record, writer);
            log.info("发送报文的核心内容【xml】:" + writer.toString());

            // 写入表【WMS_IF_POSTBACK】
            Writer writerPostback = new StringWriter();
            Marshaller msPostback = jc.createMarshaller();
            msPostback.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, false);
            msPostback.marshal(record, writerPostback);
            sendXML = writerPostback.toString();
            log.info("【报检】请求报文的核心内容【xml】:" + sendXML);
        } catch (Exception e) {
            e.printStackTrace();
            sendFlag = false;
            sendXML = "转成XML出错";
            log.error(sendXML);
        }
        // 【更新回写表】回传内容
        ifPostback.setPostbackContent(sendXML);
        ifPostbackService.updateOne(ifPostback);

        // 【发送SAP核心报文】
        if(sendFlag) {
        	String backXML = null;
        	ZDT_080_Rsp rsp = null;
        	try {
        		String url = protocolHead + ip + checkUrl;
        		
        		ZDT_080_Req req = new ZDT_080_Req();
        		req.setHeader(header);									// 消息头
        		req.setRecords(new ZDT_080_ReqRecordsItems[]{record});	// 记录
        		
        		ZSI_080_WMS2SAP_OutProxy proxy = new ZSI_080_WMS2SAP_OutProxy();
        		proxy.setEndpoint(url);
        		rsp = proxy.ZSI_080_WMS2SAP_Out(req);
        	} catch (Exception e) {
        		e.printStackTrace();
        		backXML = "将报文推送至SAP异常";
        		log.error(backXML);
        	}
        	
        	ZDT_080_RspRecord rspRESULT = null;
        	if(rsp != null) {
        		try {
        			rspRESULT = rsp.getRecord();
        			
        			// 格式化生成的XML报文
        			Writer writer = new StringWriter();
        			JAXBContext jc = JAXBContext.newInstance(ZDT_080_RspRecord.class);
        			Marshaller ms = jc.createMarshaller();
        			ms.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        			ms.setProperty(Marshaller.JAXB_ENCODING, "utf-8");
        			ms.marshal(rspRESULT, writer);
        			log.info("【报检】返回报文的核心内容【xml】:" + writer.toString());
        			
        			// 写入表【WMS_IF_POSTBACK】
        			Writer writerPostback = new StringWriter();
        			Marshaller msPostback = jc.createMarshaller();
        			msPostback.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, false);
        			msPostback.marshal(rspRESULT, writerPostback);
        			backXML = writerPostback.toString();
        		} catch (Exception e) {
        			e.printStackTrace();
        			backXML = "转成XML出错";
        			log.error(backXML);
        		}
        	}
        	// 【更新回写表】返回信息
        	ifPostback.setReturnMessage(backXML);
        	ifPostbackService.updateOne(ifPostback);
        	return rspRESULT;
        } else {
        	return null;
        }
    }

	/**
	 * 【更新检验单】
	 * 	
	 * @param record		回传信息
	 * @param qmsOqcId		检验单ID
	 * @param loginName		报检人
	 * @return
	 */
	private int updateQmsOqc(ZDT_080_RspRecord record, Integer qmsOqcId, String loginName) {
		QmsOqc qmsOqc = new QmsOqc();
		qmsOqc.setInspectionPerson(loginName);	// 报检人
		qmsOqc.setInspectionTime(new Date());	// 报检时间
		qmsOqc.setInspectionStatus(QmsOqcStatusEnum.ALREADLY_CHECKED.getCode());	// 报检状态=202【已报检】
		qmsOqc.setSapAufnr(record.getAUFNR());
		qmsOqc.setSapResult(record.getRESULT());
		qmsOqc.setSapMsg(record.getMSG());
		qmsOqc.setSapMblnr1(record.getMBLNR1());
		qmsOqc.setSapMblnr2(record.getMBLNR2());
		qmsOqc.setOqcId(qmsOqcId);
		int row = qmsOqcMapper.updateById(qmsOqc);
		return row;
	}
    
    /**
     * 获得当前时间【年月日】
     * 
     * @return
     */
    private String getDateStr() {
        Date now = new Date();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
        String dateStr = formatter.format(now);
        return dateStr;
    }

    /**
     * 获得当前时间【时分秒】
     * 
     * @return
     */
    private String getTimeStr() {
        Date now = new Date();
        SimpleDateFormat formatter = new SimpleDateFormat("HHmmss");
        String timeStr = formatter.format(now);
        return timeStr;
    }
}
